package mybatis.utils;

import mybatis.cfg.Mapper;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class Executor {

    public <T> List<T> selectList(Mapper mapper, Connection conn) {
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        try {
            String queryString = mapper.getQueryString();
            String resultType = mapper.getResultType();
            final Class<?> domain = Class.forName(resultType);
            //获取preparedStatement
            pstm = conn.prepareStatement(queryString);
            //执行sql，获取结果集
            resultSet = pstm.executeQuery();
            //封装结果集
            List<T> lists = new ArrayList<>();

            while(resultSet.next()){
                //实例化要封装的实体类对象
                T obj = (T)domain.getDeclaredConstructor().newInstance();
                //取出结果集的元信息：ResultSetMetaData
                ResultSetMetaData metaData = resultSet.getMetaData();
                //取出总列数
                int count = metaData.getColumnCount();
                //遍历
                for (int i = 1; i <= count; i++) {
                    //获取每列的名称，列名的序号是从1开始的
                    String columnName = metaData.getColumnName(i);
                    //根据列名获取值
                    Object objectValue = resultSet.getObject(columnName);
                    //给obj赋值：使用Java内省机制（借助PropertyDescriptor实现属性的封装）
                    PropertyDescriptor descriptor = new PropertyDescriptor(columnName, domain);
                    //获取写入方法
                    Method method = descriptor.getWriteMethod();
                    //把获取的列的值，给对象赋值
                    method.invoke(obj,objectValue);
                }
                lists.add(obj);
            }
            return lists;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            release(pstm,resultSet);
        }

    }

    public void release(PreparedStatement pstm,ResultSet rs){
        if(pstm != null){
            try {
                pstm.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
